package com.wei.czz.framework.admin.controller;

import java.io.IOException;
import java.util.*;

import com.alibaba.excel.EasyExcel;
import com.wei.czz.common.annotation.Auth;
import com.wei.czz.common.annotation.Resubmit;
import com.wei.czz.common.dto.admin.role.RoleDto;
import com.wei.czz.common.dto.admin.role.RolePageEnumDto;
import com.wei.czz.common.dto.common.UploadDto;
import com.wei.czz.common.easyexcel.listener.ObjectUploadListener;
import com.wei.czz.common.enums.CommonEnum;
import com.wei.czz.common.enums.common.dict.DictEnum;
import com.wei.czz.common.enums.admin.dept.BusinessTypeEnum;
import com.wei.czz.common.jsr303.group.OrderSearch;
import com.wei.czz.common.jsr303.group.Save;
import com.wei.czz.common.jsr303.group.Update;
import com.wei.czz.common.property.BatchProperty;
import com.wei.czz.common.tool.PageDto;
import com.wei.czz.common.tool.Result;
import com.wei.czz.common.utils.ExcelUtils;
import com.wei.czz.common.vo.admin.role.RoleUploadVo;
import com.wei.czz.common.vo.common.UpdateStatusVo;
import com.wei.czz.common.vo.admin.role.RoleFormVo;
import com.wei.czz.common.vo.admin.role.RoleVo;
import com.wei.czz.framework.admin.manager.RoleManager;
import com.wei.czz.framework.admin.service.RoleService;
import lombok.AllArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;

/**
 * Created by IntelliJ IDEA.
 *
 * @author wei
 * date: 2021-03-15 10:28:29
 * className: MenuController 系统角色操作请求接口类
 * version: 1.0
 * description:
 */
@RestController
@RequestMapping("sys/role")
@AllArgsConstructor
public class RoleController {

    private static final Logger log = LoggerFactory.getLogger(RoleController.class);

    private final BatchProperty batchProperty;

    private final RoleService roleService;

    private final RoleManager roleManager;


    /**
     * 保存角色数据接口
     *
     * <p>
     * 调用方：
     *  1、浏览器-后台管理页-部门与角色页-角色操作弹出框中调用
     * <p>
     * 此接口会校验是否重复提交
     * @param roleVo 角色参数对象
     * @return 不返回数据
     */
    @Resubmit(message = "保存角色")
    @PostMapping("/save")
    @Auth(permit = "system:role:save")
    public Result<Object> saveRole(@Validated(Save.class) @RequestBody RoleVo roleVo) {
        log.info("开始保存角色数据业务。{}", roleVo);

        roleManager.saveRole(roleVo);

        log.info("保存角色信息业务结束");
        return Result.success();
    }

    /**
     * 上传角色接口
     * <p>
     * 调用方：
     *  1、浏览器-后台-角色管理页面-上传抽屉中调用
     * <p>
     * 此接口会校验是否重复提交
     * @param file 文件对象
     * @return 结果
     */
    @Resubmit(spEL = "'uploadRole' + #userId", message = "上传角色")
    @PostMapping("/upload")
    @Auth(permit = "system:role:save")
    public Result<UploadDto<RoleUploadVo>> uploadRole(@RequestParam MultipartFile file) {
        log.info("开始上传角色业务。fileName={} fileSize={}", file.getOriginalFilename(), file.getSize());

        ObjectUploadListener<RoleUploadVo> objectUploadListener = new ObjectUploadListener<>();
        try {
            // 解析数据
            EasyExcel.read(file.getInputStream(), RoleUploadVo.class, objectUploadListener)
                    .sheet()
                    .doRead();
        } catch (IOException e) {
            log.error("角色上传文件解析异常。message={}", e.getMessage(), e);
            return Result.fail();
        }

        if (objectUploadListener.isEmpty()) {
            log.info("角色导入文件内容为空");
            return Result.clientFail("角色导入文件内容不能为空");
        }
        if (batchProperty.getMaxSize() < objectUploadListener.getTotal()) {
            log.warn("角色导入数量超限。batch.maxSize={} list.size={}", batchProperty.getMaxSize(),
                    objectUploadListener.getTotal());
            return Result.clientFail("一次导入角色操作最多允许同时导入" + batchProperty.getMaxSize() + "个角色");
        }

        UploadDto<RoleUploadVo> uploadDto = roleManager.uploadRole(objectUploadListener);

        log.info("上传角色业务结束");
        return Result.success(uploadDto);
    }

    /**
     * 获取角色接口
     * <p>
     * 调用方：
     *  1、浏览器-后台管理页-部门管理页-部门与角色管理页-部门关联角色弹出框中调用
     *  2、浏览器-后台管理页-用户授权弹出框中调用
     *  3、浏览器-后台管理页-根据角色选择用户弹出框中调用
     * @return 角色列表
     */
    @GetMapping("/list")
    @Auth(permit = { "system:role:save", "blog:audit:group:manage"})
    public Result<List<RoleDto>> getDeptRoleList() {
        log.info("开始获取角色业务");

        List<RoleDto> roleList = roleManager.getRoleList();

        log.info("获取角色业务结束");
        return Result.success(roleList);
    }

    /**
     * 分页查询角色数据接口
     * 根据部门主键及其他参数，查询部门关联的角色数据
     * <p>
     * 调用方：
     *  1、浏览器-后台管理页面-角色管理页面调用
     * <p>
     * 此接口会校验是否重复提交
     * @param roleVo 角色参数对象
     * @return 角色分页数据
     */
    @Resubmit(spEL = "'getPageDeptRoleList' + #userId + '-' + #roleVo", message = "分页查询角色")
    @PostMapping("/page/list")
    @Auth(permit = { "system:role:list" })
    public Result<PageDto<RoleDto>> getPageDeptRoleList(@Validated(OrderSearch.class) @RequestBody RoleFormVo roleVo){
        log.info("开始分页获取系统角色列表业务。{}", roleVo);

        PageDto<RoleDto> page = roleManager.getPageDeptRoleList(roleVo);

        log.info("分页获取系统角色列表业务结束");
        return Result.success(page);
    }

    /**
     * 获取角色管理页面参数接口
     * <p>
     * 调用方：
     *  1、浏览器-后台管理页面-角色管理页面调用
     * @return 结果
     */
    @GetMapping("/page/param")
    @Auth(permit = "system:role:list")
    public Result<RolePageEnumDto> getRolePageParam() {
        log.info("开始获取角色管理页面参数业务");

        RolePageEnumDto rolePageEnumDto = roleManager.getRolePageParam();

        log.info("获取角色管理页面参数业务结束");
        return Result.success(rolePageEnumDto);
    }

    /**
     * 获取枚举配置的角色列表接口
     * <p>
     * 调用方
     *  1、浏览器-后台管理页面-博客审核分组管理页面-博客审核分组用户管理抽屉中调用
     * @param dictValue 枚举值
     * @return 结果
     */
    @GetMapping("/dict/list")
    @Auth(permit = { "blog:audit:group:manage" })
    public Result<List<RoleDto>> getDictRoleList(@RequestParam("dictValue") Integer dictValue) {
        log.info("开始获取枚举配置的角色列表业务。dictValue={}", dictValue);

        DictEnum dictEnum = DictEnum.getDict(dictValue);
        if (Objects.isNull(dictEnum)) {
            return Result.clientFail("字典值错误");
        }

        List<RoleDto> list = roleManager.getDictRoleList(dictEnum);

        log.info("获取枚举配置的角色列表业务结束");
        return Result.success(list);
    }

    /**
     * 获取角色下一个默认排序等级接口
     * 根据部门主键，获取部门关联角色的下一个默认排序等级
     * <p>
     * 调用方：
     *  1、浏览器-后台管理页面-角色管理页-角色操作弹出框中调用
     *
     * @return 角色下一个默认排序等级数值
     */
    @GetMapping("/next/sort")
    @Auth(permit = "system:role:info")
    public Result<Integer> getNextSort() {
        log.info("开始获取下一个默认排序等级业务");

        Integer nextSort = roleService.getNextSort();

        log.info("获取下一个默认排序等级业务结束");
        return Result.success(nextSort);
    }

    /**
     * 下载角色导入模板接口
     * @param response 响应对象
     * @return 结果
     */
    @GetMapping("/download/upload-template")
    @Auth(permit = "system:role:save")
    public Result<Object> downloadUploadTemplate(HttpServletResponse response) {
        log.info("开始下载角色导入模板业务");

        RoleUploadVo roleUploadVo = new RoleUploadVo();
        roleUploadVo.setSerial(CommonEnum.ONE.getValue());
        roleUploadVo.setRoleName("测试角色");
        roleUploadVo.setRoleKey("testKey");
        roleUploadVo.setBusinessTypeName(BusinessTypeEnum.ORG.getName());
        roleUploadVo.setSort(CommonEnum.ONE.getValue());

        ExcelUtils.writeResponse("角色导入模板", Collections.singletonList(roleUploadVo),
                roleUploadVo.getTemplatePropertyList(), RoleUploadVo.class, response);

        log.info("下载角色导入模板业务结束");
        return null;
    }

    /**
     * 修改角色信息接口
     * <p>
     * 调用方：
     *  1、浏览器-后台管理页-角色管理页面-角色操作弹出框中调用
     * <p>
     * 此接口会校验是否重复提交
     * @param roleVo 角色参数对象
     * @return 不返回数据
     */
    @Resubmit(message = "修改系统角色")
    @PostMapping("/update")
    @Auth(permit = "system:role:update")
    public Result<Object> updateRole(@Validated(Update.class) @RequestBody RoleVo roleVo) {
        log.info("开始修改角色业务。{}", roleVo);

        roleManager.updateRole(roleVo);

        log.info("修改角色业务结束");
        return Result.success();
    }

    /**
     * 修改角色状态接口
     * <p>
     * 调用方：
     *  1、浏览器-后台管理页-部门与角色页-角色操作弹出框中调用
     * <p>
     * 此接口会校验是否重复提交
     * @param updateStatusVo 参数对象
     * @return 不返回数据
     */
    @Resubmit(message = "修改角色状态")
    @PostMapping("/update/status")
    @Auth(permit = "system:role:update")
    public Result<Object> updateRoleStatus(@Validated @RequestBody UpdateStatusVo updateStatusVo) {
        log.info("开始修改角色状态业务。{}", updateStatusVo);

        roleManager.updateRoleStatus(updateStatusVo);

        log.info("修改角色状态业务结束");
        return Result.success();
    }

    /**
     * 删除角色接口
     * 根据角色主键列表，批量删除角色数据
     * <p>
     * 调用方：
     *  1、浏览器-后台管理页-部门管理页-部门关联角色管理弹出框中调用
     *  2、浏览器-后台管理页-部门与角色页中调用
     *  3、浏览器-后台管理页-角色管理页面调用
     * <p>
     * 此接口会校验是否重复提交
     * @param roleIdList 角色主键列表
     * @return 结果
     */
    @Resubmit(message = "删除角色")
    @DeleteMapping("/delete")
    @Auth(permit = "system:dept-role:delete")
    public Result<Object> delete(@RequestBody List<Long> roleIdList) {
        log.info("开始删除角色业务。roleIdList={}", roleIdList);
        if (roleIdList.isEmpty()) {
            return Result.clientFail("角色主键列表不能为空");
        }
        if (batchProperty.getMaxSize() < roleIdList.size()) {
            log.warn("角色删除条数超限。batch.size={} size={}", batchProperty.getMaxSize(), roleIdList.size());
            return Result.clientFail("一次删除最多允许删除" + batchProperty.getMaxSize() + "条数据");
        }

        roleManager.deleteRole(roleIdList);

        log.info("删除角色业务结束");
        return Result.success();
    }

}
